package cn.wecloud.im.multiplayervideodemo.act

import android.Manifest
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.app.Activity
import android.app.AlertDialog
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.media.AudioManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import android.view.View
import android.view.animation.AccelerateInterpolator
import android.widget.EditText
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.animation.addListener
import androidx.core.content.ContextCompat
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import cn.wecloud.im.core.im.IMClient
import cn.wecloud.im.multiplayervideodemo.App
import cn.wecloud.im.multiplayervideodemo.R
import cn.wecloud.im.multiplayervideodemo.ext.loadAvatar
import cn.wecloud.im.multiplayervideodemo.live.*
import cn.wecloud.im.multiplayervideodemo.utils.AppSharePre
import com.github.ajalt.timberkt.Timber
import com.xwray.groupie.GroupieAdapter
import io.livekit.android.room.track.Track
import io.livekit.android.room.track.VideoTrack
import io.livekit.android.util.flow
import kotlinx.android.synthetic.main.activity_multiple_video.*
import kotlinx.coroutines.flow.*
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*

@SuppressLint("SimpleDateFormat")
class MultipleVideoActivity : AppCompatActivity() {

    companion object {
        const val KEY_ARGS = "args"

        fun getIntent(context: Context, args: MultiVideoArgs): Intent {
            return Intent(context, MultipleVideoActivity::class.java).apply {
                putExtra(KEY_ARGS, args)
            }
        }
    }

    var calling = false

    private val args: MultiVideoArgs by lazy {
        intent.getParcelableExtra(KEY_ARGS) as? MultiVideoArgs
            ?: throw NullPointerException("token is null!")
    }

    val viewModel: MultipleVideoViewModel by viewModelByFactory {
        MultipleVideoViewModel(App.MEDIA_SERVICE_URL, args, application)
    }

    val focusChangeListener = AudioManager.OnAudioFocusChangeListener {}

    private var isToolbarOpen = true
    private var timePassed = 0L
    private val dateFormat: DateFormat by lazy {
        val df = SimpleDateFormat("mm:ss")
        df.timeZone = TimeZone.getTimeZone("UTC")
        df
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_multiple_video)

        calling = true

        if (args.clientId == AppSharePre.getClientId()) {
            //发起人是自己先显示呼叫页面，等待有人同意后显示
            initCallOutView()
        }

        initAudioManager()
        //单人模式
        initSingleMode()
        //列表模式
        initListMode()
        //通用按钮
        initGeneralButton()

        requestPermissions()
    }

    private fun requestPermissions() {
        val requestPermissionLauncher =
            registerForActivityResult(
                ActivityResultContracts.RequestMultiplePermissions()
            ) { grants ->
                for (grant in grants.entries) {
                    if (!grant.value) {
                        Toast.makeText(
                            this, "Missing permission: ${grant.key}",
                            Toast.LENGTH_SHORT
                        ).show()
                        return@registerForActivityResult
                    }
                }
                viewModel.initRtc()
            }
        val neededPermissions = listOf(Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA)
            .filter {
                ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_DENIED
            }
            .toTypedArray()
        if (neededPermissions.isNotEmpty()) {
            requestPermissionLauncher.launch(neededPermissions)
        } else {
            viewModel.initRtc()
        }
    }

    private fun initCallOutView() {
        lifecycleScope.launchWhenCreated {
            viewModel.videoMembers.map { videoMembers ->
                videoMembers.filter { it?.clientId != AppSharePre.getClientId() }.filterNotNull()
            }.collect {
                callOutView.setInviteeUsersInfo(it)
            }
        }
        callOutView.visibility = View.VISIBLE
        callOutView.setOnActionListener(object : CommingCallOutView.OnActionListener {

            override fun onRejectClick(v: View?) { //拒接
                //挂断
                videoHangUp()
            }

            override fun onCameraToggleClick(v: View?) {
                viewModel.flipCamera()
            }

            override fun onVoiceToggleClick(v: View?) {
                viewModel.setMicEnabled(tvVideoVoice.isSelected)
            }

            override fun onSpeakerToggleClick(v: View?) {
                speakerToggle()
            }

            override fun onScreenMinClick(v: View?) {
                //最小化  切换为浮动窗口
            }

        })
    }

    private fun initAudioManager() {
        val audioManager = getSystemService(AUDIO_SERVICE) as AudioManager
        with(audioManager) {
            isSpeakerphoneOn = true
            isMicrophoneMute = false
            mode = AudioManager.MODE_IN_COMMUNICATION
        }
        val result = audioManager.requestAudioFocus(
            focusChangeListener,
            AudioManager.STREAM_VOICE_CALL,
            AudioManager.AUDIOFOCUS_GAIN,
        )
        if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
            tvVideoSpeaker.isSelected = true
            Timber.v { "Audio focus request granted for VOICE_CALL streams" }
        } else {
            tvVideoSpeaker.isSelected = false
            Timber.v { "Audio focus request failed" }
        }
    }

    private fun initSingleMode() {
        //初始化主成员
        initMainParticipant()
        //初始化次成员
        initSecondParticipant()
        //底部用户头像列表
        val userListAdapter = GroupieAdapter()
        lifecycleScope.launchWhenCreated {
            viewModel.room
                .combine(viewModel.videoMembers) { room, videoMembers ->
                    //过滤自己
                    room to videoMembers.filter { it?.clientId != AppSharePre.getClientId() }
                }.collect { (room, videoMembers) ->
                    if (room != null) {
                        val items = videoMembers.mapNotNull { videoMember ->
                            if (videoMember != null) VideoUserItem(videoMember) else null
                        }
                        userListAdapter.update(items)
                    }
                }
        }
        //列表模式切换按钮
        ivSwitchList.setOnClickListener {
            tvVideoTitle.isVisible = false
            vMultipleBg.isVisible = true
            videoViewContainer.isVisible = true
        }
        //用户列表  切换主镜头
        rvUserList.adapter = userListAdapter
        userListAdapter.setOnItemClickListener { item, view ->
            if (item is VideoUserItem) {
                viewModel.changePrimaryParticipant(item.videoMember)
            }
        }
    }

    private fun initListMode() {
        //列表模式背景
        vMultipleBg.isVisible = false
        //列表RV
        videoViewContainer.isVisible = false

        val gridParticipantAdapter = GroupieAdapter()
        gridParticipantAdapter.setOnItemClickListener { item, view ->
            if (item is GridParticipantItem) {
                //切回单人模式
                viewModel.changePrimaryParticipant(item.videoMember)
                tvVideoTitle.isVisible = true
                vMultipleBg.isVisible = false
                videoViewContainer.isVisible = false
            }
        }
        videoViewContainer.adapter = gridParticipantAdapter
        videoViewContainer.layoutManager = GridLayoutManager(this, 2, RecyclerView.VERTICAL, false)
        //列表模式成员视频
        lifecycleScope.launchWhenCreated {
            viewModel.room
                .combine(viewModel.videoMembers) { room, videoMembers -> room to videoMembers }
                .collect { (room, videoMembers) ->
                    if (room != null) {
                        val items = videoMembers.mapNotNull { videoMember ->
                            if (videoMember != null)
                                GridParticipantItem(room, videoMember)
                            else
                                null
                        }
                        gridParticipantAdapter.update(items)
                    }
                }
        }
    }

    private fun initGeneralButton() {
        //TODO 最小化
        ivVideoMin.isInvisible = true
        //通话计时
        tvVideoTime.postDelayed(object : Runnable {
            override fun run() {
                timePassed++
                val time = dateFormat.format(timePassed * 1000)
                tvVideoTime.text = time
                tvVideoTime.postDelayed(this, 1000)
            }
        }, 1000)
        //镜头切换
        ivCameraSwitch.setOnClickListener { viewModel.flipCamera() }
        //底部工具栏开关
        ivToolbarToggle.setOnClickListener { toolbarToggle() }
        //静音
        viewModel.micEnabled.observe(this) { enabled ->
            tvVideoVoice.setOnClickListener { viewModel.setMicEnabled(!enabled) }
            tvVideoVoice.isSelected = !enabled
        }
        //扬声器
        tvVideoSpeaker.setOnClickListener { speakerToggle() }
        //挂断
        tvVideoHangUp.setOnClickListener { videoHangUp() }
        //摄像头开关
        viewModel.cameraEnabled.observe(this) { enabled ->
            tvVideoCamera.setOnClickListener { viewModel.setCameraEnabled(!enabled) }
            tvVideoCamera.isSelected = enabled
            ivCameraSwitch.isEnabled = enabled
        }
        //添加成员
        tvVideoAddMember.setOnClickListener {
            addMemberDialog()
        }

        lifecycleScope.launchWhenCreated {
            viewModel.videoStatus.collect {
                when (it) {
                    MultipleVideoViewModel.VideoStatus.prepare -> {
                        //呼叫等待界面
                        if (args.clientId == AppSharePre.getClientId())
                            callOutView.isVisible = true
                    }
                    MultipleVideoViewModel.VideoStatus.start -> {
                        if (args.clientId == AppSharePre.getClientId())
                            callOutView.isVisible = false
                    }
                    MultipleVideoViewModel.VideoStatus.end -> {
                        calling = false
                        finish()
                    }
                }
            }
        }
    }

    private fun addMemberDialog() {
        val etClientId = EditText(this)
        val builder = AlertDialog.Builder(this)
        builder.setTitle("请输入邀请的ClientId").setIcon(android.R.drawable.ic_dialog_info)
            .setView(etClientId)
            .setNegativeButton("取消", null)
        builder.setPositiveButton(
            "确认"
        ) { dialog, which ->
            val clientId = etClientId.text.toString().trim()
            if (TextUtils.isEmpty(clientId)) {
                return@setPositiveButton
            }
            viewModel.meetInvite(listOf(clientId))
        }
        builder.show()
    }

    override fun onResume() {
        super.onResume()
        lifecycleScope.launchWhenResumed {
            viewModel.error.collect {
                Log.e(TAG, "viewModel.error:${it.toString()}")
                if (it != null) {
                    Toast.makeText(this@MultipleVideoActivity, "Error: $it", Toast.LENGTH_LONG)
                        .show()
                    viewModel.dismissError()
                }
            }
        }
    }


    override fun onDestroy() {
        super.onDestroy()
        GridParticipantItem.releaseRenderers()
        // Release video views
        flFullScreenSurface.release()
        flFloatSurface.release()

        // Undo audio mode changes
        val audioManager = getSystemService(AUDIO_SERVICE) as AudioManager
        with(audioManager) {
            abandonAudioFocus(focusChangeListener)
            mode = AudioManager.MODE_NORMAL
        }
    }

    private val TAG = "MultipleVideoActivity"

    //初始化单人模式主成员
    private fun initMainParticipant() {
        //主镜头渲染
        lifecycleScope.launchWhenCreated {
            viewModel.room.filterNotNull().take(1)
                .transform { room ->
                    // 初始化视频渲染
                    room.initVideoRenderer(flFullScreenSurface)
                    //观察主参与者
                    emitAll(viewModel.mainVideoMember)
                }.flatMapLatest { mainVideoMember ->
                    //更新新的主镜头身份信息
                    ivBgAvatar.loadAvatar("")
                    tvVideoTitle.text = mainVideoMember?.clientId

                    // 订阅videoTracks
                    if (mainVideoMember != null) {
                        mainVideoMember::participant.flow
                    } else {
                        emptyFlow()
                    }
                }
                .flatMapLatest { participant ->
                    if (participant != null) {
                        participant::videoTracks.flow.map { participant to it }
                    } else {    //成员还没有视频显示背景图
                        flowOf(null to null)
                    }
                }
                .flatMapLatest { (participant, videoTracks) ->
                    //优先考虑任何屏幕共享流。
                    val trackPublication =
                        participant?.getTrackPublication(Track.Source.SCREEN_SHARE)
                            ?: participant?.getTrackPublication(Track.Source.CAMERA)
                            ?: videoTracks?.values?.firstOrNull()
                            ?: return@flatMapLatest flowOf(null to null)
                    combine(trackPublication::muted.flow, trackPublication::track.flow)
                    { muted, track -> muted to track }
                }.collect { (muted, videoTrack) ->
                    // 清理旧videoTracks
                    val oldVideoTrack = flFullScreenSurface.tag as? VideoTrack
                    oldVideoTrack?.removeRenderer(flFullScreenSurface)
                    //将新videoTracks绑定到视频视图。
                    if (muted == false && videoTrack is VideoTrack) {
                        videoTrack.addRenderer(flFullScreenSurface)
                        flFullScreenSurface.visibility = View.VISIBLE
                        tvNotOpenCamera.isVisible = false
                        ivBgAvatar.isVisible = false
                    } else {
                        flFullScreenSurface.visibility = View.INVISIBLE
                        tvNotOpenCamera.isVisible = true
                        ivBgAvatar.isVisible = true
                    }
                    flFullScreenSurface.tag = videoTrack
                }
        }
    }

    //初始化单人模式次成员
    private fun initSecondParticipant() {
        //自己的浮动视图
        lifecycleScope.launchWhenCreated {
            viewModel.room.filterNotNull().take(1)
                .transform { room ->
                    // 初始化视频渲染
                    room.initVideoRenderer(flFloatSurface.getRenderer())
                    //观察自己
                    emitAll(viewModel.secondVideoMember)
                }.flatMapLatest { videoMember ->
                    flFloatSurface.setIdentity(videoMember?.clientId)
                    // 订阅videoTracks
                    if (videoMember != null) {
                        videoMember::participant.flow
                    } else {
                        emptyFlow()
                    }
                }
                .flatMapLatest { participant ->
                    if (participant != null) {
                        participant::videoTracks.flow.map { participant to it }
                    } else {
                        flowOf(null to null)
                    }
                }
                .flatMapLatest { (participant, videoTracks) ->
                    //优先考虑任何屏幕共享流。
                    val videoTrackPublication =
                        participant?.getTrackPublication(Track.Source.SCREEN_SHARE)
                            ?: participant?.getTrackPublication(Track.Source.CAMERA)
                            ?: videoTracks?.values?.firstOrNull()
                            ?: return@flatMapLatest flowOf(null to null)
                    combine(videoTrackPublication::muted.flow, videoTrackPublication::track.flow)
                    { muted, track -> muted to track }
                }.collect { (muted, videoTrack) ->
                    // 清理旧videoTracks
                    val oldVideoTrack = flFloatSurface.tag as? VideoTrack
                    oldVideoTrack?.removeRenderer(flFloatSurface.getRenderer())
                    //将新videoTracks绑定到视频视图。
                    if (muted == false && videoTrack is VideoTrack) {
                        videoTrack.addRenderer(flFloatSurface.getRenderer())
                        flFloatSurface.setVideoOff(false)
                    } else {
                        flFloatSurface.setVideoOff(true)
                    }
                    flFloatSurface.tag = videoTrack
                }
        }
        //音频状态
        lifecycleScope.launchWhenCreated {
            viewModel.secondVideoMember
                .filterNotNull()
                .flatMapLatest { videoMember -> videoMember::participant.flow }
                .filterNotNull()
                .flatMapLatest { participant -> participant::audioTracks.flow }
                .flatMapLatest { tracks ->
                    val audioTracks = tracks.values.firstOrNull()
                    if (audioTracks != null) {
                        audioTracks::muted.flow
                    } else {
                        flowOf(true)
                    }
                }.collect { muted ->
                    flFloatSurface.setAudioOff(muted)
                }
        }
    }

    //底部工具栏开关
    private fun toolbarToggle() {
        val fromY = clBottomToolbar.translationY
        val height = clBottomToolbar.height.toFloat()
        val animation = AnimatorSet().apply {
            interpolator = AccelerateInterpolator()
            duration = 300
        }
        animation.addListener(onEnd = {
            isToolbarOpen = clBottomToolbar.translationY == 0f
            ivToolbarToggle.setImageResource(if (isToolbarOpen) R.mipmap.icon_bottom_close else R.mipmap.icon_bottom_open)
        })
        val offset = height - fromY
        animation.playTogether(
            //底部工具栏
            ObjectAnimator.ofFloat(ivToolbarToggle, "translationY", offset),
            ObjectAnimator.ofFloat(clBottomToolbar, "translationY", offset),

            ObjectAnimator.ofFloat(ivSwitchList, "translationY", offset),
            ObjectAnimator.ofFloat(rvUserList, "translationY", offset)
        )
        animation.start()
    }

    //扬声器切换
    private fun speakerToggle() {
        //免提
        val audioManager = getSystemService(AUDIO_SERVICE) as AudioManager
        try {
            if (tvVideoSpeaker.isSelected) {
                tvVideoSpeaker.isSelected = false
                if (audioManager.isSpeakerphoneOn) audioManager.isSpeakerphoneOn = false
                audioManager.mode = AudioManager.MODE_IN_COMMUNICATION
            } else {
                tvVideoSpeaker.isSelected = true
                if (!audioManager.isSpeakerphoneOn)
                    audioManager.isSpeakerphoneOn = true
                audioManager.mode = AudioManager.MODE_IN_COMMUNICATION
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    private fun videoHangUp() {
        viewModel.meetHangUp()
    }

}